package com.xiaoma.aes.encryption.asymmetrical;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.xiaoma.aes.util.BaseUtil;
import lombok.extern.slf4j.Slf4j;

public class DecodeTool{
    
    

    /**
     * 私钥解密
     * 
     * @param data 十六进制密文串
     * @param key 私钥 ，十六进制
     * @return String
     * @since 0.0.1
     * @author ranqi
     * @throws Exception
     */
    public static String decryptByPrivateKey(String data, String key){
        
        /* 对私钥解密 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(key);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        
        KeyFactory keyFactory;
        Key privateKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        }catch(NoSuchAlgorithmException e){
//            log.error("系统异常:解密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.KEY_ALGORTHM + ")不存在");
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        Cipher cipher = null;
        try{
            cipher = Cipher.getInstance(Encrytion.CIPHER_ALGORTHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:解密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在");
        }catch(NoSuchPaddingException e){
//            LOGGER.error("系统异常:解密算法 错误", e);
//            throw new EncryptionException("系统异常:解密算法错误", e);
        }catch(InvalidKeyException e){
//            LOGGER.error("业务异常: 秘钥 获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        /* 分段解密 */
        int max = Encrytion.MAX;
        
        if(BaseUtil.objectNotNull(data)){
            
            /* 对密文进行分段先分段 */
            String [] rs = data.split("\\" + Encrytion.SPLIT);
            
            int len = 0;
            // 组合byte[]
            byte [] result = new byte[rs.length * max];
            
            try{
                for(int i = 0; i < rs.length; i++){
                    byte [] bs;
                    
                    bs = cipher.doFinal(BaseUtil.parseHexStr2Byte(rs[i]));
                    
                    BaseUtil.arraycopy(bs, 0, result, i * max, bs.length);
                    len += bs.length;
                }
            }catch(IllegalBlockSizeException e){
//                LOGGER.error("业务异常: 解密 错误", e);
//                throw new EncryptionException("业务异常: 秘钥获取失败", e);
            }catch(BadPaddingException e){
//                LOGGER.error("业务异常:  解密 错误", e);
//                throw new EncryptionException("业务异常: 秘钥获取失败", e);
            }
            byte [] newResult = new byte[len];
            BaseUtil.arraycopy(result, 0, newResult, 0, len);
            
            /* 还原字符串 */
            try{
                return new String(newResult, Encrytion.CHARSET);
            }catch(UnsupportedEncodingException e){
//                LOGGER.error("业务异常: 解密 错误,字符编码(" + Encrytion.CHARSET + ")不支持", e);
//                throw new EncryptionException("业务异常: 解密错误,字符编码{0}不支持", e, Encrytion.CHARSET);
            }
        }
        
        return null;
    }
    
    /**
     * 公钥解密
     * 
     * @param data 十六进制密文串
     * @param key 公钥 ，十六进制
     * @return String
     * @since 0.0.1
     * @author ranqi
     * @throws Exception
     */
    public static String decryptByPublicKey(String data, String key){
        
        /* 对私钥解密 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(key);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        
        KeyFactory keyFactory;
        Key publicKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:解密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.KEY_ALGORTHM + ")不存在");
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥 获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        Cipher cipher = null;
        try{
            cipher = Cipher.getInstance(Encrytion.CIPHER_ALGORTHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:解密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在");
        }catch(NoSuchPaddingException e){
//            LOGGER.error("系统异常:解密算法错误,", e);
//            throw new EncryptionException("系统异常:解密算法错误", e);
        }catch(InvalidKeyException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        
        /* 对密文进行分段先分段 */
        String [] rs = data.split("\\" + Encrytion.SPLIT);
        
        /* 分段解密 */
        int max = Encrytion.MAX;
        
        if(BaseUtil.objectNotNull(rs)){
            int len = 0;
            // 组合byte[]
            byte [] result = new byte[rs.length * max];
            
            try{
                for(int i = 0; i < rs.length; i++){
                    byte [] bs;
                    
                    bs = cipher.doFinal(BaseUtil.parseHexStr2Byte(rs[i]));
                    
                    BaseUtil.arraycopy(bs, 0, result, i * max, bs.length);
                    len += bs.length;
                }
            }catch(IllegalBlockSizeException e){
//                LOGGER.error("业务异常: 解密错误,,", e);
//                throw new EncryptionException("业务异常: 秘钥获取失败", e);
            }catch(BadPaddingException e){
//                LOGGER.error("业务异常:  解密错误", e);
//                throw new EncryptionException("业务异常: 秘钥获取失败", e);
            }
            byte [] newResult = new byte[len];
            BaseUtil.arraycopy(result, 0, newResult, 0, len);
            
            /* 还原字符串 */
            try{
                return new String(newResult, Encrytion.CHARSET);
            }catch(UnsupportedEncodingException e){
//                LOGGER.error("业务异常: 解密错误,字符编码(" + Encrytion.CHARSET + ")不支持", e);
//                throw new EncryptionException("业务异常: 解密错误,字符编码" + Encrytion.CHARSET + "不支持", e);
            }
        }
        
        return null;
    }
    
    /*    public static void main(String [] args){
        String data = "3EAAA2B50B8A02D9E1AC6A790E318B42CB03FC5E33271BF98F7C73C0EF634C799C5A9F3BBA1C0050837B555989D445E9332C0EAA7059E980EF28E81FCEC0A030859A14D0D28C333739FDC02D80B68E15A41EF36D3DA7632531C02B12EF2B2308488C384A9DFBCC9733FB051555BA182FC3E9AE0658019F85652B23CBB7359C3E";
        String key = "30820276020100300D06092A864886F70D0101010500048202603082025C0201000281810085C0D9C461CA9E3088505E1F0C7635837EB8CA939738369A3757F2199026C52CF37A8D4BE489E70639AADB92B26D445155870481A068E7C400F2E0D4F3FE851FCD35A983CE6EE64F3464557F65988D87D2F73DD24510711BDCDF67F4F9A01A82DB94D43EA0ACABBB7C26AD17C88B5BFF77ADA1D59E6B3E6178659927674783E30203010001028180437D6D24CFA77AACC88BAD0283BA3E046CF3F79C0388E4DC6A22A151CED0115C3E3B4F82C4FDE4A9DA7D61302382491FB5455CBBBFE24F5832965B6678FBABD6063F116B84C6B67F6F79DA9CFDC8520B4CB7AB9374174ACB6A1F9833DA51CB8E3F9B4D48E6CD00AC0662B8F81FBD8A8FA75E309EFA272FDED669E55C5D04EBF1024100C1256412DBF18D395ABA541E6E40F2EEC324DA591117B6379B9D5B471C07479B46A1763EB1C97F2FC40730630666FED99395262AEEC53C7D15A8B7E6379FB1B9024100B1479211945C3C6700E13562F9D3246FAF98BA7A5BEB4CB3F4FF5CD87466E68D4AF24ABECDDF01671E143C7428A2050EA6E2BC14E0631142338E5D177506207B02405D418B771BA11E79F1D783640A01EC09E248F9F00533B8B452BB8065EE1F89B06C42EB4FCC11A90A4C10D889077F554F8255824F3A681B139E108F7265AB0269024100A14AF7C80CCEBA9A10BFD65DDDE4CFF2D9B5C07C51234D5F31DA20B4437BD7E9D7B58871FF4715B4A7364C26774DAA0241AE6AE7279C9AF83B861C869A0F5FFF024040AC650B3B5570281822A34F45D1F6FC676AEF252DFF92C39DE750835CA5815D9ECED1160AC29D706718F8D3F817DD55A466F4C7FA5F01DC635609B6678B680B";
        System.out.println(decryptByPrivateKey(data, key));
    }*/
}
